package de.stalinski.login;

import de.stalinski.logging.FrbrLogger;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SessionCheck implements Runnable {

    private static SessionCheck SessionCheck;
    private Thread t;
    private boolean RUNNING = false;
    private CopyOnWriteArrayList<Client> clients = new CopyOnWriteArrayList();
    private Lock lock = new ReentrantLock();

    private SessionCheck() {
        if (t == null) {
            t = new Thread(this);
        } else if (t != null && !t.isInterrupted()) {
            t.interrupt();
        }
        RUNNING = true;
        t.start();
    }

    public void updateDuration(String session) {
        for (Client c : clients) {
            if (c.getSessionID().equals(session)) {
            }
        }
    }

    public static SessionCheck instance() {
        if (SessionCheck == null) {
            SessionCheck = new SessionCheck();
        }
        return SessionCheck;
    }

    public boolean addToList(Client client) {
        boolean result = false;
        if (!isAlreadyInList(client)) {
            clients.add(client);
            result = true;
            if (!RUNNING) {
                RUNNING = true;
                t = new Thread(this);
                t.start();
            }
        }
        return result;
    }

    public void removeFromList(String user, String sessionID) {
        for(Client c : clients) {
            if(c.getUser().equals(user)&&c.getSessionID().equals(sessionID)) {
                clients.remove(c);
                FrbrLogger.instance().log(FrbrLogger.instance().LOG_INFO, "Removed user "+user);
                break;
            }
        }
    }

    public boolean isAlreadyInList(Client client) {
        boolean result = false;
        for (Client c : clients) {
            if (c.getSessionID().equals(client.getSessionID()) && c.getUser().equals(client.getUser())) {
                result = true;
                FrbrLogger.instance().log(FrbrLogger.instance().LOG_ERR, "User " + client.getUser() + " with id " + client.getSessionID() + " not added, cause user is already in list!");
            }
        }
        return result;
    }

    private void checkStateAndCleanUp(Client client) {
        if (isInactive(client)) {
            clients.remove(client);
            FrbrLogger.instance().log(FrbrLogger.instance().LOG_INFO, "User " + client.getUser() + " removed, caused by session-timeout!");
        }
    }

    public boolean sessionActive(String user, String sessionID) {
        boolean result = false;
        for (Client c : clients) {
            if (c.getUser().equals(user) && c.getSessionID().equals(sessionID)) {
                result = true;
            }
        }
        return result;
    }

    private boolean isInactive(Client client) {
        boolean result = false;
        if (System.currentTimeMillis() >= client.getSessionDuration()) {
            result = true;
        }
        return result;
    }

    public boolean checkInactivityFor(String user, String sessionID) {
        boolean result = false;
        for (Client c : clients) {
            if (c.getSessionID().equals(sessionID) && c.getUser().equals(user)) {
                result = isInactive(c);
                break;
            }
        }
        return result;
    }

    public void stopMe() {
        RUNNING = false;
        t.interrupt();
        FrbrLogger.instance().log(FrbrLogger.instance().LOG_INFO, "Output stopped, cause there are no clients connected!");
    }

    public void run() {
        while (RUNNING) {
            try {
                for (Client c : clients) {
                    checkStateAndCleanUp(c);
                //c.output();
                }

                t.sleep(1000);

                if (clients.size() == 0) {
                    stopMe();
                }

            // Blockierende Datenbankabfrage (Darum auch InterruptedException)
            } catch (final InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
